/**
 * @file   Server.h
 * @author Djuro Drljaca (djurodrljaca@gmail.com)
 * @date   2013-03-14
 * @brief  DataBus Server.
 *
 * Copyright (C) 2013  Djuro Drljaca <djurodrljaca@gmail.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef LIBDATABUS_SERVER_SERVER_H
#define LIBDATABUS_SERVER_SERVER_H

#include <DataBus/Common/Common.h>
#include <DataBus/Server/Client.h>
#include <QtCore/QObject>
#include <QtNetwork/QTcpServer>
#include <QtCore/QList>

namespace DataBus
{
/**
 * @brief The Server class
 */
class DATABUSSHARED_EXPORT Server : public QObject
{
    Q_OBJECT

public:
    /**
     * @brief Constructor for Server
     *
     * @param parent    Parent object
     */
    explicit Server(QObject *parent = 0);

    /**
     * @brief Descructor for Server
     */
    virtual ~Server();

    /**
     * @brief Starts the Server on the specified TCP port
     *
     * @param port  TCP port
     *
     * @retval true     OK
     * @retval false    Error
     */
    bool start(quint16 port = 60000);

    /**
     * @brief Stops the Server
     */
    void stop();

    /**
     * @brief Checks if Server is started
     *
     * @retval true     Started
     * @retval false    Not started
     */
    bool isStarted() const;

    /**
     * @brief Returns the number of clients on the server
     *
     * @return Number of clients on the server
     */
    int getClientCount() const;

    /**
     * @brief Get Client by index
     *
     * @param index     Index in Client List
     *
     * @retval Client   Pointer to a Client object
     * @retval 0        Error
     */
    const Client * getClient(const int index) const;

    /**
     * @brief Get Client by Client ID
     *
     * @param clientId  Client ID
     *
     * @retval Client   Pointer to a Client object
     * @retval 0        Error
     */
    const Client * getClientById(quint8 clientId) const;

    /**
     * @brief Get Client Index
     *
     * @param client    Pointer to a client object
     *
     * @retval index    Client index
     * @retval -1       Error
     */
    int getClientIndex(const Client *client) const;

signals:
    /**
     * @brief Server received a packet that was not processed internally.
     *
     * @param packet    DataBus Packet
     */
    void newPacketReceived(const Packet packet);

protected:
    /**
     * @brief Returns pointer to Client List
     *
     * @return Pointer to Client List
     */
    const QList<Client *> * getClientList();

    /**
     * @brief Removes all Clients from the list
     */
    virtual void removeAllClients();

    /**
     * @brief Add Client to the list
     *
     * @param client    New Client object
     */
    virtual void addClient(Client *client);

    /**
     * @brief Remove Client from the list
     *
     * @param index Client's index in the list
     *
     * @retval true     Success
     * @retval false    Error
     */
    virtual bool removeClient(const int index);

    /**
     * @brief Tries to register the client
     *
     * @param client    Client that requested to be registered
     * @param packet    Register Client Request packet
     *
     * @retval RETURN_STATUS_SUCCESS            Success
     * @retval RETURN_STATUS_INVALID_CLIENT_ID  Error
     */
    virtual quint8 registerClient(const Client *client, const Packet &packet);

    /**
     * @brief Process all received Packets from Client
     *
     * @param client
     */
    virtual void processPackets(Client *client);

    /**
     * @brief Forward received packet to a client
     *
     * @param packet    DataBus Packet
     */
    virtual void forwardPacket(const Packet &packet);

private slots:
    /**
     * @brief This slot should be executed when a new Client connects to this Server
     */
    void newClientConnected();

    /**
     * @brief This slot should be executed when a Client disconnects from this Server
     */
    void clientDisconnected(Client *client);

    /**
     * @brief This slot should be executed when a Client receives a new Packet
     *
     * @param client    DataBus Client
     */
    void processReceivedPacket(Client *client);

private:
    /**
     * @brief Get Registered Client ID list
     *
     * @return Registered Client ID list
     */
    QList<quint8> getRegisteredClientIdList() const;

    /**
     * @brief Get Registered Client Status
     *
     * @param clientId  Client ID
     *
     * @return Client's status
     */
    ClientStatus getRegisteredClientStatus(const quint8 clientId) const;

    /**
     * @brief TCP server
     */
    QTcpServer m_tcpServer;

    /**
     * @brief List of Clients
     */
    QList<Client *> m_clients;
};
}

#endif // LIBDATABUS_SERVER_SERVER_H
